package com.joymart.compute.rest;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.joymart.common.model.Range;
import com.joymart.common.system.BusinessConfig;
import com.joymart.common.utils.DatetimeUtils;
import com.joymart.common.utils.SecurityUtils;
import com.joymart.compute.model.AmountAggregation;
import com.joymart.compute.model.MonthlyGroupPv;
import com.joymart.compute.model.OrderGain;
import com.joymart.compute.model.PvAggregation;
import com.joymart.compute.service.MonthlyGroupPvService;
import com.joymart.compute.service.OrderGainService;
import com.joymart.compute.service.ReconciliationService;
import com.joymart.qualification.model.AdvanceEvaluation;
import com.joymart.qualification.model.AdvanceEvaluationRecord;
import com.joymart.qualification.model.ShopEvaluation;
import com.joymart.qualification.service.AdvanceEvaluationPersistingService;
import com.joymart.qualification.service.ApplicationService;
import com.joymart.qualification.service.ShopEvaluationService;
import com.joymart.user.model.BusinessRole;
import com.joymart.user.model.CachedUser;
import com.joymart.user.service.UserCacheManager;
import com.joymart.user.service.UserService;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;
import java.math.MathContext;
import java.time.LocalDateTime;
import java.time.Month;
import java.util.*;
import java.util.stream.IntStream;

import static com.joymart.user.model.BusinessRole.AG_CSR;
import static com.joymart.user.model.BusinessRole.AU_CSR;

/**
 * 用户的统计数据
 */
@RestController
public class UserStatsController {

    @Autowired
    private ShopEvaluationService evaluationService;
    @Autowired
    private OrderGainService orderGainService;
    @Autowired
    private ReconciliationService reconciliationService;
    @Autowired
    private UserCacheManager userCacheManager;
    @Autowired
    private AdvanceEvaluationPersistingService advanceEvaluationPersistingService;
    @Autowired
    private BusinessConfig businessConfig;
    @Autowired
    private MonthlyGroupPvService monthlyGroupPvService;
    @Autowired
    private ApplicationService applicationService;
    @Autowired
    private ObjectMapper objectMapper;
    @Autowired
    private UserService userService;


    /**
     * 开店资格
     * @return
     */
    @GetMapping("/vitality/points/mine")
    public Object myVitalityPointsMine() {
        String currentUserId = SecurityUtils.getCurrentUserId();
        ShopEvaluation shopEvaluation = evaluationService.evaluateShop(currentUserId);
        if(shopEvaluation.isQualified() && userCacheManager.get(currentUserId).getHighestRole()== AG_CSR){
            //升级顾客
            userService.modifyHighestRole( userCacheManager.get(currentUserId).getUser(), AU_CSR);
        }
        if(!shopEvaluation.isQualified() && userCacheManager.get(currentUserId).getHighestRole()== BusinessRole.AU_CSR){
            userService.modifyHighestRole( userCacheManager.get(currentUserId).getUser(), AG_CSR);
        }

        boolean existPending = applicationService.existPending(currentUserId, BusinessRole.AG_SHOP);
        return new JSONObject(objectMapper.convertValue(shopEvaluation, Map.class)).put("existPending", existPending);
    }

    /**
     * 收益数据
     * @param start
     * @param end
     * @return
     */
    @GetMapping("/profitsAndGains")
    public Object getProfitGains(LocalDateTime start, LocalDateTime end) {
        Range range = Range.of(start, end);
        String userId = SecurityUtils.getCurrentUserId();
        CachedUser cachedUser = userCacheManager.get(userId);
        Map<String,Object> map = new LinkedHashMap<>();
        cachedUser.getBusinessRoles().forEach(role -> {
            if(role == BusinessRole.AG_SHOP){
                map.put("AG_SHOP_PROFIT", orderGainService.aggregateFirstSellerProfit(userId, range));
            }else if(role == BusinessRole.AU_SHOP){
                map.put("AU_SHOP_PROFIT",orderGainService.aggregateSecondSellerProfit(userId, range));
            }else {
               OrderGain.Type.formRole(role).ifPresent(type -> map.put(type.name(),
                       Optional.ofNullable(orderGainService.aggregateOrderGain(userId, type, range))
                               .map(this::convertPvToAmount)
                               .get()));
            }
        });
        BigDecimal grand = map.values().stream().map(AmountAggregation.class::cast).map(AmountAggregation::getAmount)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        map.put("grand", grand);
        return map;
    }



    /**
     * 对账数据
     */
    @GetMapping("/reconciliation")
    public Object computeReconciliation(LocalDateTime start, LocalDateTime end) {
        Range range = Range.of(start, end);
        String userId = SecurityUtils.getCurrentUserId();
        return reconciliationService.computeReconciliation(userId, range) ;
    }

    /**
     * 晋升进度
     * @return
     */
    @GetMapping("/promotion/condition")
    public Object getCurrentPromotionCondition() {
        String currentUserId = SecurityUtils.getCurrentUserId();
        BusinessRole highestRole = userCacheManager.get(currentUserId).getHighestRole();
        switch (highestRole) {
            case AG_CSR,AU_CSR -> {
                return Map.of("message", "店铺用户才能进行晋升评估");
            }
            case AG_SHOP, AU_SHOP, AG_WHS, AU_WHS, AG_AGENT, AU_AGENT, MANAGER, AG_DIRECTOR -> {
                AdvanceEvaluationRecord evaluationResult = advanceEvaluationPersistingService
                        .getLatestEvaluationResult(currentUserId,highestRole.next());
                if (evaluationResult != null) {
                    return evaluationResult;
                }
            }
            case AU_DIRECTOR -> {
                return Map.of("message","您已升至最高身份");
            }
        }
        return Map.of("message", "暂无数据,请次日查看");
    }


    /**
     * 晋升进度
     * @return
     */
    @GetMapping("/monthlyPv/condition")
    public Object getMonthlyCondition() {
        String currentUserId = SecurityUtils.getCurrentUserId();
        CachedUser user = userCacheManager.get(currentUserId);

        if(!user.getBusinessRoles().contains(BusinessRole.AG_WHS)){
            return Map.of("message", "批发商以下不考核业绩");
        }

        BusinessRole scale = user.getBusinessRoles().contains(BusinessRole.AG_AGENT) ? BusinessRole.AG_AGENT : BusinessRole.AG_WHS;
        LocalDateTime now = DatetimeUtils.now();
        Range range = now.getMonth() == Month.JANUARY?DatetimeUtils.year(now.minusYears(1)) :DatetimeUtils.year(now);
        List<MonthlyGroupPv> list = monthlyGroupPvService.findMonthlyGroupPv(user, scale, range);
        BigDecimal spec = scale == BusinessRole.AG_AGENT?businessConfig.getAgentPvSpec():businessConfig.getWhsPvSpec();
        return MonthlyPvConditionDto.annualMap(scale,spec,range,list);
    }

    /**
     * 积分聚合转换成金额聚合
     * @param pvAggregation
     * @return
     */
    private AmountAggregation convertPvToAmount(PvAggregation pvAggregation) {
        AmountAggregation amountAggregation = new AmountAggregation();
        amountAggregation.setOrderCount(pvAggregation.getOrderCount());
        amountAggregation.setAmount(pvAggregation.getPvSum().multiply(businessConfig.getPvCashRate(),
                MathContext.DECIMAL64));
        return amountAggregation;
    }

    @Data
    @AllArgsConstructor
    private static class MonthlyPvConditionDto {
        private LocalDateTime month;
        private BigDecimal monthlyPv;
        private BigDecimal spec;
        public boolean isComplete(){
            return monthlyPv.compareTo(spec) >= 0;
        }

        public static Map<String,Object> annualMap(BusinessRole scale, BigDecimal spec, Range range, List<MonthlyGroupPv> list) {
            Map<LocalDateTime, BigDecimal> pvMap = new HashMap<>();
            list.forEach(p->pvMap.put(p.getMonth(), p.getAmount().setScale(2, BigDecimal.ROUND_HALF_EVEN)));

            List<MonthlyPvConditionDto> monthDtos = IntStream.range(0, 12).boxed()
                    .map(i -> range.getStart().plusMonths(i))
                    .map(m -> new MonthlyPvConditionDto(m, pvMap.getOrDefault(m, BigDecimal.ZERO.setScale(2)), spec))
                    .toList();
            return Map.of("scale", scale, "data", monthDtos);

        }
    }
}
